﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace Acoris.Parser.Aml
{
    /// <summary>
    /// 表示Aml文档的词法分析状态
    /// </summary>
    public enum AmlLexState : int
    {
        /// <summary>
        /// 
        /// </summary>
        EmptyState = 0,

        /// <summary>
        /// 
        /// </summary>
        TagOpenState = 1,

        /// <summary>
        /// 
        /// </summary>
        BeforeTagNameState = 2,

        /// <summary>
        /// 
        /// </summary>
        AfterTagOpenState = 3,

        /// <summary>
        /// 
        /// </summary>
        AttributeNameState = 4,

        /// <summary>
        /// 
        /// </summary>
        AttributeNameCloseState = 5,

        /// <summary>
        /// 
        /// </summary>
        AttributeValueState = 6,

        /// <summary>
        /// 
        /// </summary>
        BeforeDeclareCloseState = 7,

        /// <summary>
        /// 
        /// </summary>
        BeforeCloseState = 8,

        /// <summary>
        /// 
        /// </summary>
        TextState = 9,

        /// <summary>
        /// 
        /// </summary>
        CommentState = 10,

        /// <summary>
        /// 
        /// </summary>
        EntityState = 11,

        /// <summary>
        /// 
        /// </summary>
        AfterTagNameState = 12,

        /// <summary>
        /// 
        /// </summary>
        CDATAState = 13,

        /// <summary>
        /// 
        /// </summary>
        AttributeValueCloseState = 14,
    }

    /// <summary>
    /// 表示Aml词法分析状态基类
    /// </summary>
    public abstract class AmlLexicalAnalysisState : DFAState<AmlTokenType>
    {
        public AmlLexicalAnalysisState(AmlLexState stateid) : base((int)stateid) { }

        public new AmlLexState State {
            get {
                return (AmlLexState)base.State;
            }
        }
    }

    /// <summary>
    /// 表示起始状态
    /// </summary>
    public sealed class AmlEmptyState : AmlLexicalAnalysisState
    {
        /// <summary>
        /// 
        /// </summary>
        public AmlEmptyState() : base(AmlLexState.EmptyState) { }

        /// <summary>
        /// 
        /// </summary>
        public override string StateName { get => "EmptyState"; }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="collection"></param>
        /// <param name="stateStack"></param>
        /// <param name="stream"></param>
        /// <param name="state"></param>
        /// <param name="lastToken"></param>
        /// <param name="nowToken"></param>
        /// <returns></returns>
        public override DFAState<AmlTokenType> Action(
            ICollection<TokenBase<AmlTokenType>> collection, StateStack<AmlTokenType> stateStack, CharacterStream stream,
            DFAState<AmlTokenType> state,ref TokenBase<AmlTokenType> lastToken,ref TokenBase<AmlTokenType> nowToken)
        {

            //---------------------------------------------------------------------------------------------------
            //  进入当前状态之后
            //  1) 当状态堆栈为空时 寻找 '<'字符
            //  2) 当状态堆栈不为空时，将栈头的状态弹出，还原上一个状态
            //---------------------------------------------------------------------------------------------------

            if (stateStack.Empty) {
                for (; !stream.EndOfFile; stream.Move(1)) {
                    if (stream.Current() == '<') {
                        break;
                    }
                }

                state = this;
                var nextState = this[stream.Current()];
                stream.Move(1);
                return nextState;
            }

            // 还原状态信息
            // 
            var frame = stateStack.Pop();
            state = frame.LastState;
            //lastToken = frame.LastToken;
            //nowToken = frame.Token;
            return frame.CurrentState;
        }
    }

    /// <summary>
    /// 表示标记开始状态
    /// </summary>
    public sealed class AmlTagOpenState : AmlLexicalAnalysisState
    {
        public AmlTagOpenState() : base(AmlLexState.TagOpenState) { }

        /// <summary>
        /// 
        /// </summary>
        public override string StateName { get => "TagOpenState"; }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="collection"></param>
        /// <param name="stateStack"></param>
        /// <param name="stream"></param>
        /// <param name="state"></param>
        /// <param name="last"></param>
        /// <param name="now"></param>
        /// <returns></returns>
        public override DFAState<AmlTokenType> Action(
             ICollection<TokenBase<AmlTokenType>> collection, StateStack<AmlTokenType> stateStack, CharacterStream stream,
             DFAState<AmlTokenType> state, ref TokenBase<AmlTokenType> lastToken, ref TokenBase<AmlTokenType> nowToken)
        {

            //---------------------------------------------------------------------------------------------------
            //  进入当前状态之后:
            //  1) 寻找第一个非空格字符
            //
            //  按照字符分类，可进入的后继状态有:
            //  1) Anyword,             BeforeTagNameState
            //  2) '/',                 DeclareTagCloseState
            //  3) '!',                 CommentState            
            //---------------------------------------------------------------------------------------------------
            for (; !stream.EndOfFile; stream.Move(1)) {
                var ch = stream.Current();
                if(ch != '\r' && ch != '\n' && ch != '\x20') {
                    break;
                }
            }



            state = this;//设置当前状态为下一个状态的前继状态
            
            // Anyword在这里实现
            if (stream.IsAnyWord()) {
                return this['\0'];
            }
            var nextState = this[stream.Current()];
            stream.Move(1);
            return nextState;
        }
    }

    /// <summary>
    /// 表示前标签名状态
    /// </summary>
    public sealed class AmlBeforeTagNameState : AmlLexicalAnalysisState
    {
        public AmlBeforeTagNameState() : base( AmlLexState.BeforeTagNameState) { }

        public override string StateName { get => "BeforeTagNameState"; }

        public override DFAState<AmlTokenType> Action(
            ICollection<TokenBase<AmlTokenType>> collection, StateStack<AmlTokenType> stateStack, CharacterStream stream,
            DFAState<AmlTokenType> state, ref TokenBase<AmlTokenType> lastToken, ref TokenBase<AmlTokenType> nowToken)
        {

            //---------------------------------------------------------------------------------------------------
            //  进入当前状态之后，读取标签名，并生成相应的TOKEN
            //---------------------------------------------------------------------------------------------------
            var start = stream.Position;
            var length = 0;
            for (; !stream.EndOfFile; stream.Move(1),length++) {
                if (!stream.IsAnyWord()) {
                    break;
                }
            }
            lastToken = new AmlToken(AmlTokenType.BeforeTagName, start, length, stream.Text)
            {
                StateOpen = (state.State == (int)AmlLexState.BeforeTagNameState) || (state.State == (int)AmlLexState.TextState)
            };
            collection.Add(lastToken);

            state = this;
            var nextState = this[stream.Current()];
            stream.Move(1);
            return nextState;
        }
    }

    /// <summary>
    /// 表示后标签打开状态
    /// </summary>
    public sealed class AmlAfterTagOpenState : AmlLexicalAnalysisState
    {
        public AmlAfterTagOpenState() : base(AmlLexState.AfterTagOpenState)
        {

        }

        public override string StateName { get => "AfterTagOpenState"; }

        public override DFAState<AmlTokenType> Action(
            ICollection<TokenBase<AmlTokenType>> collection, StateStack<AmlTokenType> stateStack, CharacterStream stream, 
            DFAState<AmlTokenType> state, ref TokenBase<AmlTokenType> lastToken, ref TokenBase<AmlTokenType> nowToken)
        {

            //---------------------------------------------------------------------------------------------------
            //  进入当前状态之后，寻找第一个AnyWord
            //---------------------------------------------------------------------------------------------------
            for (; !stream.EndOfFile; stream.Move(1)) {
                if (stream.IsAnyWord()) {
                    break;
                }else if(stream.Current() == '>' && lastToken != null) {
                    Debug.WriteLine(lastToken);
                    collection.Add(lastToken);
                    lastToken = null;
                }
            }

            if (stream.IsAnyWord()) {
                return this['\0'];
            }

            state = this;
            var nextState = this[stream.Current()];
            stream.Move(1);
            return nextState;
        }
    }

    /// <summary>
    /// 表示后标签名状态
    /// </summary>
    public sealed class AmlAfterTagNameState : AmlLexicalAnalysisState
    {
        /// <summary>
        /// 
        /// </summary>
        public AmlAfterTagNameState() : base(AmlLexState.AfterTagNameState) { }

        public override string StateName { get => "AfterTagNameState"; }

        public override DFAState<AmlTokenType> Action(
            ICollection<TokenBase<AmlTokenType>> collection, StateStack<AmlTokenType> stateStack, CharacterStream stream,
            DFAState<AmlTokenType> state, ref TokenBase<AmlTokenType> lastToken, ref TokenBase<AmlTokenType> nowToken)
        {

            //---------------------------------------------------------------------------------------------------
            //  进入当前状态之后需要读取后标签名
            //---------------------------------------------------------------------------------------------------
            var start = stream.Position;
            var length = 0;
            for (; !stream.EndOfFile; stream.Move(1), length++) {
                if (!stream.IsAnyWord()) {
                    break;
                }
            }
            lastToken = new AmlToken(AmlTokenType.AfterTagName, start, length, stream.Text)
            {
                StateClose = true
            };
            collection.Add(lastToken);

            state = this;
            var nextState = this[stream.Current()];
            stream.Move(1);
            return nextState;
        }
    }

    /// <summary>
    /// 表示属性名状态
    /// </summary>
    public sealed class AmlAttributeNameState : AmlLexicalAnalysisState
    {
        public AmlAttributeNameState() : base( AmlLexState.AttributeNameState) {}

        public override string StateName { get => "AttributeNameState"; }

        public override DFAState<AmlTokenType> Action(
            ICollection<TokenBase<AmlTokenType>> collection, StateStack<AmlTokenType> stateStack, CharacterStream stream,
            DFAState<AmlTokenType> state, ref TokenBase<AmlTokenType> lastToken, ref TokenBase<AmlTokenType> nowToken)
        {

            //---------------------------------------------------------------------------------------------------
            //  进入当前状态之后，持续读取string直到读取到'='
            //---------------------------------------------------------------------------------------------------
            var start = stream.Position;
            var length = 0;
            for (; !stream.EndOfFile; stream.Move(1),length++) {
                if(stream.Current() == '=') {
                    break;
                }
            }            

            //完成TOKEN的创建
            nowToken = new AmlToken(AmlTokenType.AttributeName, start, length, stream.Text)
            {
                StateClose = true,
                StateOpen = true
            };
            Debug.WriteLine(nowToken);
            collection.Add(nowToken);

            state = this;
            var nextState = this[stream.Current()];
            stream.Move(1);
            return nextState;
        }
    }

    /// <summary>
    /// 表示离开属性名标签状态
    /// </summary>
    public sealed class AmlAttributeNameCloseState : AmlLexicalAnalysisState
    {
        /// <summary>
        /// 
        /// </summary>
        public AmlAttributeNameCloseState() : base(AmlLexState.AttributeNameCloseState) { }

        public override string StateName { get => "AttributeNameCloseState"; }

        public override DFAState<AmlTokenType> Action(
            ICollection<TokenBase<AmlTokenType>> collection, StateStack<AmlTokenType> stateStack, CharacterStream stream, 
            DFAState<AmlTokenType> state, ref TokenBase<AmlTokenType> lastToken, ref TokenBase<AmlTokenType> nowToken)
        {
            state = this;
            var nextState = this[stream.Current()];
            stream.Move(1);
            return nextState;
        }
    }

    /// <summary>
    /// 表示属性值状态
    /// </summary>
    public sealed class AmlAttributeValueState : AmlLexicalAnalysisState
    {
        public AmlAttributeValueState() : base(AmlLexState.AttributeValueState) { }

        public override string StateName { get => "AttributeValueState"; }

        public override DFAState<AmlTokenType> Action(
            ICollection<TokenBase<AmlTokenType>> collection, StateStack<AmlTokenType> stateStack, CharacterStream stream, 
            DFAState<AmlTokenType> state, ref TokenBase<AmlTokenType> lastToken, ref TokenBase<AmlTokenType> nowToken)
        {
            //---------------------------------------------------------------------------------------------------
            //  进入当前状态之后读取第一个'"'
            //---------------------------------------------------------------------------------------------------
            var length = 0;
            var start = stream.Position;
            for (; !stream.EndOfFile; stream.Move(1), length++) {
                if (stream.Current() == '"') {
                    break;
                }
            }
            nowToken = new AmlToken(AmlTokenType.AttributeValue, start, length, stream.Text);
            collection.Add(nowToken);

            state = this;
            var nextState = this[stream.Current()];
            stream.Move(1);
            return nextState;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public sealed class AmlAttributeValueCloseState : AmlLexicalAnalysisState
    {
        public AmlAttributeValueCloseState() : base(AmlLexState.AttributeValueCloseState) { }

        public override string StateName { get => "AttributeValueCloseState"; }

        public override DFAState<AmlTokenType> Action(
            ICollection<TokenBase<AmlTokenType>> collection, StateStack<AmlTokenType> stateStack, CharacterStream stream,
            DFAState<AmlTokenType> state, ref TokenBase<AmlTokenType> lastToken, ref TokenBase<AmlTokenType> nowToken)
        {
            state = this;
            var nextState = this[stream.Current()];
            stream.Move(1);
            return nextState;
        }
    }

    /// <summary>
    /// 表示前标签进入关闭状态
    /// </summary>
    public sealed class AmlBeforeDeclareCloseState : AmlLexicalAnalysisState
    {
        /// <summary>
        /// 
        /// </summary>
        public AmlBeforeDeclareCloseState() : base(AmlLexState.BeforeDeclareCloseState) { }

        public override string StateName { get => "BeforeDeclareCloseState"; }

        public override DFAState<AmlTokenType> Action(
            ICollection<TokenBase<AmlTokenType>> collection, StateStack<AmlTokenType> stateStack, CharacterStream stream, 
            DFAState<AmlTokenType> state, ref TokenBase<AmlTokenType> lastToken, ref TokenBase<AmlTokenType> nowToken)
        {
            //---------------------------------------------------------------------------------------------------
            //  进入当前状态之后:
            //  
            //---------------------------------------------------------------------------------------------------
            //这里lastToken只传递BeforeTagNameState创建的TOKEN
            if (state.State == (int)AmlLexState.BeforeDeclareCloseState) {
                lastToken.StateClose = true;
                lastToken = null;
            }

            state = this;
            var nextState = this[stream.Current()];
            stream.Move(1);
            return nextState;
        }
    }

    /// <summary>
    /// 表示前标签关闭状态
    /// </summary>
    public sealed class AmlBeforeCloseState : AmlLexicalAnalysisState
    {
        public AmlBeforeCloseState() : base(AmlLexState.BeforeCloseState) { }

        public override string StateName { get => "BeforeCloseState"; }

        public override DFAState<AmlTokenType> Action(
            ICollection<TokenBase<AmlTokenType>> collection, StateStack<AmlTokenType> stateStack, CharacterStream stream,
            DFAState<AmlTokenType> state, ref TokenBase<AmlTokenType> lastToken, ref TokenBase<AmlTokenType> nowToken)
        {
            if (state.State == (int)AmlLexState.BeforeDeclareCloseState && lastToken != null) {
                // 如果之前状态为BeforeDeclareCloseState
                // 那么lastToken可以闭包了
                lastToken.StateClose = true;
            }

            state = this;
            var nextState = this[stream.Current()];
            stream.Move(1);
            return nextState;
        }
    }

    /// <summary>
    /// 表示文本标签
    /// </summary>
    public sealed class AmlTextState : AmlLexicalAnalysisState
    {
        public AmlTextState() : base(AmlLexState.TextState) { }

        public override string StateName { get => "TextState"; }

        public override DFAState<AmlTokenType> Action(
            ICollection<TokenBase<AmlTokenType>> collection, StateStack<AmlTokenType> stateStack, CharacterStream stream,
            DFAState<AmlTokenType> state, ref TokenBase<AmlTokenType> lastToken, ref TokenBase<AmlTokenType> nowToken)
        {

            //---------------------------------------------------------------------------------------------------
            //  进入文本状态之后需要一直移动字符流，将状态压栈，直到遇到 '<'
            //---------------------------------------------------------------------------------------------------

            // 向记号集合添加标记

            // 状态装帧
            var frame = new StateFrame<AmlTokenType>(state,this,lastToken,nowToken);
            stateStack.Push(frame);

            // 如果BeforeTagNameState没有进入BeforeCloseState
            // 则lastToken可能还存在未添加到记号集合的记号
            //if (lastToken != null) {
            //    collection.Add(lastToken);
            //    lastToken = null;
            //}

            // 读取字符
            var start = stream.Position;
            var length = 0;
            for (; !stream.EndOfFile; stream.Move(1), length++) {
                var ch = stream.Current();
                if (ch == '<' || ch == '>') {
                    break; 
                }
            }

            if (length > 0) {
                nowToken = new AmlToken(AmlTokenType.Text, start, length, stream.Text);
                collection.Add(nowToken);
            }

            state = this;
            var nextState = this[stream.Current()];
            stream.Move(1);//移动到下一位
            return nextState;
        }
    }

    /// <summary>
    /// 表示注释状态
    /// </summary>
    public sealed class AmlCommentState : AmlLexicalAnalysisState
    {
        public AmlCommentState() : base(AmlLexState.CommentState) { }

        public override string StateName { get => "CommentState"; }

        public override DFAState<AmlTokenType> Action(
            ICollection<TokenBase<AmlTokenType>> collection, StateStack<AmlTokenType> stateStack, CharacterStream stream, 
            DFAState<AmlTokenType> state, ref TokenBase<AmlTokenType> lastToken, ref TokenBase<AmlTokenType> nowToken)
        {

            //---------------------------------------------------------------------------------------------------
            //  注释状态
            //      0) 第一个dash
            //      1) 第二个dash
            //      2) 注释状态，一直读取直到遇到dash
            //      3) 第三个dash
            //      4) 第四个dash
            //      5) 退出状态
            //---------------------------------------------------------------------------------------------------

            int commentState = 0;
            
            while (!stream.EndOfFile) {
                switch (commentState) {
                    case 0:
                        switch (stream.Current()) {
                            case '-':
                                commentState = 1;
                                break;
                            case '[':
                                break;
                        }break;
                    case 1:
                        switch (stream.Current()) {
                            case '-':
                                commentState = 2;
                                break;
                            default:break;
                        }break;
                    case 2:
                        for (; !stream.EndOfFile; stream.Move(1)) {
                            if(stream.Current() == '-') {
                                break;
                            }
                        }
                        stream.Move(-1);
                        commentState = 3;
                        break;
                    case 3:
                        switch (stream.Current()) {
                            case '-':
                                commentState = 4;
                                break;
                        }break;
                    case 4:
                        switch (stream.Current()) {
                            case '-':
                                commentState = 5;
                                break;
                        }
                        break;
                    case 5:
                        goto exit;
                }
                stream.Move(1);
            }

            // 退出状态
            exit:

            state = this;
            var nextState = this[stream.Current()];
            stream.Move(1);
            return nextState;
        }
    }

    /// <summary>
    /// 表示实体引用解析状态
    /// </summary>
    public sealed class AmlEntityState : AmlLexicalAnalysisState
    {
        /// <summary>
        /// 
        /// </summary>
        public AmlEntityState() : base(AmlLexState.EntityState) { }

        /// <summary>
        /// 
        /// </summary>
        public override string StateName { get => throw new NotImplementedException(); }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="collection"></param>
        /// <param name="stateStack"></param>
        /// <param name="stream"></param>
        /// <param name="state"></param>
        /// <param name="lastToken"></param>
        /// <param name="nowToken"></param>
        /// <returns></returns>
        public override DFAState<AmlTokenType> Action(
            ICollection<TokenBase<AmlTokenType>> collection, StateStack<AmlTokenType> stateStack, CharacterStream stream, 
            DFAState<AmlTokenType> state, ref TokenBase<AmlTokenType> lastToken, ref TokenBase<AmlTokenType> nowToken)
        {
            state = this;
            var nextState = this[stream.Current()];
            stream.Move(1);
            return nextState;
        }
    }

    /// <summary>
    /// 表示CDATA解析状态
    /// </summary>
    public sealed class AmlCDATAState : AmlLexicalAnalysisState
    {
        /// <summary>
        /// 
        /// </summary>
        public AmlCDATAState() : base(AmlLexState.CDATAState) { }

        public override string StateName { get => "CDATAState"; }

        public override DFAState<AmlTokenType> Action(
            ICollection<TokenBase<AmlTokenType>> collection, StateStack<AmlTokenType> stateStack, CharacterStream stream, 
            DFAState<AmlTokenType> state, ref TokenBase<AmlTokenType> lastToken, ref TokenBase<AmlTokenType> nowToken)
        {
            state = this;
            var nextState = this[stream.Current()];
            stream.Move(1);
            return nextState;
        }
    }
}
